package model.pieces;

import java.awt.Point;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import utils.PlayerSides;

import model.Board;

/**
 * Class represent a piece on chess board. A piece holds its team and uses the game board in order to know what its possible movements are.
 * The movement is implemented according to derived class of actual chess piece   
 */
public abstract class Piece implements Cloneable {
	
	// members
	private static final short STEP = 1; // step size on board
	private PlayerSides.Sides side; // indicates piece's player 
	private short moveForward; // vertical movement forward direction, set as upwards or downwards according to piece's team	
	
	// protected methods

	/**
	 * Gets reference to the game board and piece's current position on board.
	 * Returns a list of all free positions that are reachable within one turn.
	 * @param gameBoard- reference to game board
	 * @param srcPoint- current position of piece 
	 * @return list of positions within piece's range
	 */
	protected abstract List<Point> getAvailableFreePositions(Board gameBoard, Point srcPoint);
	
	/**
	 * Returns a list of all positions holding opponent's pieces, that are within reach in 
	 * a single turn
	 * @param gameBoard- reference to game board
	 * @param srcPoint- piece's current position
	 * @return list of positions holding reachable opponents
	 */
	protected abstract List<Point> getAvailableOpponentPositions(Board gameBoard, Point srcPoint);
	
	// public methods

	/**
	 * Constructor- creates a new piece assigned to given player
	 * @param side- indicates piece's player
	 */
	public Piece(PlayerSides.Sides side) {
		
		// set piece position according to given value
		this.side = side; 
		
		// check to which direction should move on board
		if (this.side.equals(PlayerSides.Sides.White)) {
			// first player attacks from upper part of board
			moveForward = -STEP;
			
		} else {
			// second player attacks from lower part of board
			moveForward = STEP;
		}
	}
	
	/**
	 * Clones the piece
	 */
	@Override
	public abstract Piece clone();
	//
	
	/**
	 * Returns a list of all positions that the piece can reach within a single turn.
	 * Piece can move to reachable free positions or reachable positions that hold opponent's pieces
	 * @param gameBoard- reference to game board
	 * @param srcPoint- piece's current position
	 * @return list of all positions that are possible for piece's next move 
	 */
	public List<Point> getAvailableDestinations(Board gameBoard, Point srcPoint) {
		
		// initialize a new position list
		List<Point> retMoves = new LinkedList<Point>();		
		
		// add available positions that do not hold any pieces 
		retMoves.addAll(getAvailableFreePositions(gameBoard, srcPoint));
		
		// get available positions with possible opponents
		List<Point> opponentPositions = getAvailableOpponentPositions(gameBoard, srcPoint);
		
		// remove positions that were already found
		Iterator<Point> iter = opponentPositions.iterator(); // get an iterator
		while (iter.hasNext()) { // scan opponent positions
			
			// check if current position was already found
			if (retMoves.contains(iter.next())) {
				
				// position was already found, remove it
				iter.remove();
			}
		}
		
		// add available positions holding opponent's pieces (no duplicates)
		retMoves.addAll(opponentPositions);
		
		// return all positions found
		return retMoves;
	}
		
	/**
	 * Returns an indicator if piece belongs to first player or not
	 * @return True if piece belongs to first player, False if not
	 */
	public PlayerSides.Sides getPlayer() { return this.side; }
	
	/**
	 * Returns rate of vertical "forwards" movement
	 * @return step to move forwards
	 */
	public short getDirection() { return moveForward; }
	
	/**
	 * Gets another piece and check if both pieces are of the same team
	 * @param pieceToCmpr- piece to compare side to
	 * @return True if they are, False if not
	 */
	public boolean sameSide(Piece pieceToCmpr) {
		// compare pieces' teams
		return pieceToCmpr.side.equals(this.side);
	}
}